# TriggerSwitchD, executes commands to activate/deactive remote switches.
# (c) Copyright 2010 Pontus Strömdahl, AdhocSkill. 
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


require File.join(File.dirname(__FILE__),"trigger_switch_d_helper")
require File.join(File.dirname(__FILE__),"action")

module TriggerSwitchD
  #Holds actions organized by name and cronological
  #Use create to instasiate 
  module Schedule  
    module InstanceMethods
      def schedule_action(action)
        self.__insert_action__(action)
        find(action.to_s)
      end
      
      #find by name
      def find(name)
        by_name[name]
      end
      
      #Returns when the next action is scheduled to occur
      #based on the hour_minute. The format is "HH:MM" for both
      #hour_minute as well as the result, with the exception
      #that if no next action is found it will return
      #"23:59:59" 
      def next_action_at(hour_minute)
        end_of_day = "23:59:59"
        return end_of_day unless hour_minute =~ /\d{2}:\d{2}/
        time = Time.parse(hour_minute)
        cronological.keys.sort {|first,second| Time.parse(first) <=> Time.parse(second)}.find(Proc.new {end_of_day}) do |at|
          time < Time.parse(at)
        end
      end
      
      #deletes action from schedule, returning the action on exit
      def delete(name)
        action = by_name.delete(name)
        cronological[action.at].delete(name)
      end

      #Executes action and removes it from the schedule
      def execute(at,output)
        cronolog_at = cronological[at]
        cronolog_at.values.each { |action| action.execute(output) } unless cronolog_at == nil
        self.__remove_executed_actions_from_schedule__(at)
      end

      #Hash of actions accessible by "HH:MM" format
      def cronological
        self[:cronological]
      end
      
      #Hash of actions accessible by name
      def by_name
        self[:all]
      end

      def __remove_executed_actions_from_schedule__(at) #:nodoc:
        cronolog = cronological
        cronolog_at = cronolog[at]
        cronolog_at.values.clone.each do |element|
          by_name.delete(element.to_s)
        end unless cronolog_at == nil
        cronolog.delete(at)
      end

      def __insert_action__(action) #:nodoc:
        return if __action_is_scheduled__(action)
        name = action.to_s
        by_name[name] = action
        cronolog_at = cronological[action.at] ||= {}
        cronolog_at[name] = action
      end
      
      def __action_is_scheduled__(action)
        by_name.keys.include?(action.to_s)
      end
    end
    
    #Creates an instance of a schedule
    def create
      schedule = {:all => {}, :cronological => {}}.extend InstanceMethods
    end
    
    module_function :create
  end  
end